﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using XLua;

public class UnlimitedScroll : MonoBehaviour
{
    public delegate RectTransform ItemFunc(int index, Transform parent);

    [SerializeField]
    RectTransform contentRect;

    RectTransform rectTransform;
    ScrollRect scrollRect;

    ItemFunc itemFunc;

    float scrollHeight;
    float scrollWidth;

    bool inited;

    int removeCount = 10;

    class ItemData
    {
        public int index;
        public RectTransform rectTransform;
    }
    struct ItemIndex
    {
        public int minIndex;
        public float minPos;
        public float minHeight;
        public int maxIndex;
        public float maxPos;
        public float maxHeight;
    }

    List<ItemData> listItems;

    void Awake()
    {
        listItems = new List<ItemData>();
        inited = false;
        rectTransform = gameObject.GetComponent<RectTransform>();
        scrollRect = gameObject.GetComponent<ScrollRect>();
        contentRect.anchorMin = new Vector2(0,0);
        contentRect.anchorMax = new Vector2(1,0);
        contentRect.pivot = new Vector2(0, 0);
        scrollHeight = rectTransform.rect.height;
        scrollWidth = rectTransform.rect.width;
        contentRect.sizeDelta = new Vector2(0, scrollHeight);

        scrollRect.horizontal = false;
        scrollRect.vertical = true;

        ScrollRect.ScrollRectEvent scrollEvent = new ScrollRect.ScrollRectEvent();
        scrollEvent.AddListener(OnValueChange);
        scrollRect.onValueChanged = scrollEvent;
    }

    public void SetItemFunc(ItemFunc func)
    {
        itemFunc = func;
    }

   bool RemoveItemByIndex(int index)
    {
        if(listItems.Count<10)
        {
            return false;
        }
        for (int i = 0; i < listItems.Count; ++i)
        {
            if (listItems[i].index == index)
            {
                var item = listItems[i];
                GameObject.Destroy(item.rectTransform.gameObject);
                listItems.RemoveAt(i);
                break;
            }
        }
        return true;
    }

    public void SetRemoveCount(int count)
    {
        removeCount = count;
    }

    public void reloadData()
    {
        Clear();
        InitScroll();
    }

    public void reScrollData()
    {
        if (!inited)
        {
            return;
        }
        bool isUpdate = false;
        var parentPos = contentRect.anchoredPosition;
        var itemParam = GetItemIndex();
        var scrollMinPos = itemParam.minPos + parentPos.y;
        var scrollMaxPos = itemParam.maxPos + parentPos.y;
        if (scrollMinPos < -itemParam.minHeight - 30)
        {
            var isRemove = RemoveItemByIndex(itemParam.minIndex);
            if (isRemove)
                isUpdate = true;
        }
        else
        {
            int startMinIndex = itemParam.minIndex - 1;
            float startMinPos = itemParam.minPos;
            while (scrollMinPos >= 0 && startMinIndex >= 0)
            {
                var item = itemFunc(startMinIndex, contentRect.transform);
                if (item == null)
                {
                    break;
                }
                if (startMinPos <= 0)
                {
                    break;
                }
                ItemData itemData = new ItemData();
                itemData.index = startMinIndex;
                item.anchorMin = new Vector2(0.5f, 0);
                item.anchorMax = new Vector2(0.5f, 0);
                item.pivot = new Vector2(0.5f, 0);
                itemData.index = startMinIndex;
                var height = item.rect.height;
                item.anchoredPosition = new Vector2(0, startMinPos - height);
                itemData.rectTransform = item;
                listItems.Add(itemData);

                scrollMinPos = scrollMinPos - height;
                startMinPos = startMinPos - height;
                startMinIndex--;
                isUpdate = true;
            }
        }

        if (scrollMaxPos > scrollHeight + 30)
        {
            var isRemove = RemoveItemByIndex(itemParam.maxIndex);
            if (isRemove)
                isUpdate = true;
        }
        else
        {
            int startMaxIndex = itemParam.maxIndex + 1;
            float startMaxPos = itemParam.maxPos + itemParam.maxHeight;
            while (scrollMaxPos < scrollHeight)
            {
                var item = itemFunc(startMaxIndex, contentRect.transform);
                if (item == null)
                {
                    break;
                }
                ItemData itemData = new ItemData();
                itemData.index = startMaxIndex;
                item.anchorMin = new Vector2(0.5f, 0);
                item.anchorMax = new Vector2(0.5f, 0);
                item.pivot = new Vector2(0.5f, 0);
                item.anchoredPosition = new Vector2(0, startMaxPos);
                itemData.rectTransform = item;
                itemData.index = startMaxIndex;
                listItems.Add(itemData);

                var height = item.rect.height;
                scrollMaxPos = scrollMaxPos + height;
                startMaxPos = startMaxPos + height;
                startMaxIndex++;
                isUpdate = true;
            }
        }
        if (isUpdate)
        {
            float maxHeight = getMaxHeight();
            contentRect.sizeDelta = new Vector2(0, maxHeight >= scrollHeight ? maxHeight : scrollHeight);
        }
    }

    void OnValueChange(Vector2 delta)
    {
        reScrollData();
    }

    public float getMaxHeight()
    {
        float maxHeight = listItems[0].rectTransform.anchoredPosition.y + listItems[0].rectTransform.rect.height;
        for (int i = 1; i < listItems.Count; ++i)
        {
            float height = listItems[i].rectTransform.anchoredPosition.y + listItems[i].rectTransform.rect.height;
            if(height>maxHeight)
            {
                maxHeight = height;
            }
        }
        return maxHeight;
    }

    public void Clear()
    {
        inited = false;
        for (int i = 0; i < listItems.Count; ++i)
        {
            GameObject.Destroy(listItems[i].rectTransform.gameObject);
        }
        listItems.Clear();
    }

    public void InitScroll()
    {
        if(inited)
        {
            return;
        }
        Debug.Log(" public void InitScroll()");
        contentRect.anchoredPosition = new Vector2(0, 0);
        inited = true;
        int startIndex = 0;
        float startY = 0;
        float finalHeight = 0;
        while (startY < scrollHeight)
        {
            var item = itemFunc(startIndex, contentRect.transform);
            if(item == null)
            {
                break;
            }
            ItemData itemData = new ItemData();
            itemData.index = startIndex;
            item.anchorMin = new Vector2(0.5f, 0);
            item.anchorMax = new Vector2(0.5f, 0);
            item.pivot = new Vector2(0.5f, 0);
            item.anchoredPosition = new Vector2(0, startY);
            itemData.rectTransform = item;
            listItems.Add(itemData);
            var height = item.rect.height;
            startY = startY + height;
            finalHeight = finalHeight + height;
            startIndex++;
        }
        contentRect.sizeDelta = new Vector2(0, finalHeight);
    }

    ItemIndex GetItemIndex()
    {
        ItemIndex result = new ItemIndex();
        if (listItems.Count > 0)
        {
            result.minIndex = listItems[0].index;
            result.maxIndex = listItems[0].index;
            for (int i = 0; i < listItems.Count; ++i)
            {
                var item = listItems[i];
                if (item.index <= result.minIndex)
                {
                    result.minPos = item.rectTransform.anchoredPosition.y;
                    result.minIndex = item.index;
                    result.minHeight = item.rectTransform.rect.height;
                }
                if (item.index >= result.maxIndex)
                {
                    result.maxPos = item.rectTransform.anchoredPosition.y;
                    result.maxIndex = item.index;
                    result.maxHeight = item.rectTransform.rect.height;
                }
            }
        }
        else
        {
            result.minIndex = 0;
            result.maxIndex = 0;
            result.minHeight = 0;
            result.maxHeight = 0;
            result.minPos = 0;
            result.maxPos = 0;
        }
        return result;
    }
}
